﻿#pragma once

#include <GetPot>
#include <memory>
#include <string>
#include <vector>

#include "Logging.h"

// 配置文件解析器
class Parser
{
public:
  Parser(const std::string& file)
    : _file(file)
  {
    try
    {
      _cf = std::make_shared<GetPot>(_file);
    }
    catch (...)
    {
      Error("配置文件", _file, "不存在");
    }

    _sections = _cf->get_section_names();
  }
  ~Parser(){};

  virtual void Parse() {}

  void Variable(const std::string& section) { _cf->set_prefix(section); }

  bool ExistSection(const std::string& section)
  {
    auto section_names = _cf->get_section_names();
    auto it = std::find(section_names.begin(), section_names.end(), section);
    for (auto& v : section_names)
    {
      std::cout << v << '\n';
    }
    return it != section_names.end();
  }
  void SetPrefix(const std::string& prefix)
  {
    try
    {
      _cf->set_prefix(prefix);
    }

    catch (const std::exception& e)
    {
      Error(e.what());
    }
  }
  template<typename T>
  T GetValue(const std::string& name)
  {
    try
    {
      return _cf->get<T>(name);
    }
    catch (const std::exception& e)
    {
      Error(e.what());
    }
  }

  template<typename T>
  T Get(const std::string& name)
  {
    return GetValue<T>(name);
  }

  bool Have(const std::string& name) { return VariableSize(name) != 0; }

  template<typename T>
  T GetValue(const std::string& name, unsigned int idx)
  {
    auto size = VariableSize(name);
    if (size == 0)
    {
      Error(_file, "不存在", name);
    }

    return _cf->get_element<T>(name, idx, (const char*)0x0);
  }

  template<typename T>
  std::vector<T> GetVectorValue(const std::string& name)
  {
    auto size = VariableSize(name);
    if (size == 0)
    {
      Error(_file, "不存在", name);
    }

    std::vector<T> value;
    for (size_t i = 0; i < size; i++)
    {
      value.push_back(_cf->get_element<T>(name, i, (const char*)0x0));
    }
    return value;
  }

  template<typename T>
  T GetValue(const std::string& prefix, const std::string& name)
  {
    try
    {
      _cf->set_prefix(prefix);
      return _cf->get<T>(name);
    }
    catch (const std::exception& e)
    {
      Error(e.what());
    }
  }

  unsigned int VariableSize(const std::string& name)
  {
    try
    {
      return _cf->vector_variable_size(name);
    }
    catch (const std::exception& e)
    {
      Error(e.what());
    }
  }


private:
  std::string _file;
  std::shared_ptr<GetPot> _cf;
  std::vector<std::string> _sections;
};
